package com.inspur.edp.common.expr.evaluator;

import com.inspur.edp.common.expr.compile.JavaCompileService;
import com.inspur.edp.common.expr.compile.JavaSourceCode;
import com.inspur.edp.common.expr.exception.ExpressException;
import lombok.Data;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author lizhaorui
 * @date 2025/8/15
 * @description
 */

@Data
public class ScriptEvaluator implements ExpressEvaluator {

    private String javaSourceCode;
    private String javaClassName;
    private Method runMethod;

    public ScriptEvaluator(String javaSourceCode, String javaClassName) {
        this.javaSourceCode = javaSourceCode;
        this.javaClassName = javaClassName;
    }

    @Override
    public Object evaluate(Map<String, Object> dataMap) {
        if (this.runMethod == null) {
            synchronized (this) {
                if (this.runMethod == null) {
                    JavaCompileService javaCompileService = new JavaCompileService();
                    List<JavaSourceCode> javaSourceCodes = new ArrayList<>();
                    JavaSourceCode javaSourceDesc = new JavaSourceCode();
                    javaSourceDesc.setClassFullName(this.javaClassName);
                    javaSourceDesc.setSourceCode(this.javaSourceCode);
                    javaSourceCodes.add(javaSourceDesc);
                    ClassLoader classLoader = javaCompileService.compile(javaSourceCodes);
                    try {
                        Class cls = classLoader.loadClass(this.javaClassName);
                        Object object = cls.newInstance();
                        this.runMethod = this.getRunMethod(object);
                    } catch (Throwable e) {
                        throw new ExpressException("load express class occur exception.", e);
                    }
                }
            }
        }
        try {
            Object[] objects = new Object[1];
            objects[0] = dataMap;
            return this.runMethod.invoke(null, objects);
        } catch (Throwable e) {
            throw new ExpressException("execute express occur exception.", e);
        }
    }

    private Method getRunMethod(Object object) {
        Method[] methods = object.getClass().getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals("run")) {
                return method;
            }
        }
        return null;
    }

}